﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

	<head>
		<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
		<title>Caching</title>
		<link type="text/css" rel="stylesheet" href="bootstrap.min.css" />
	</head>

	<body>

		<div class="document-contents">

			<h3>Introduction</h3>

			<p>ASP.NET Boilerplate provides an abstraction for caching. It internally uses this cache abstraction. While default 
implementation uses
				<a href="https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx?f=255&amp;MSPPError=-2147217396">
MemoryCache</a>, it can be implemented and changable for any other caching 
provider. <a href="https://www.nuget.org/packages/Abp.RedisCache" target="_blank">
			Abp.RedisCache</a> package implements cache in Redis for instance 
			(see "Redis Cache Integration" section below).</p>

			<h3>ICacheManager</h3>

			<p>Main interface for caching is <strong>ICacheManager</strong>. We can 
				<a href="/Pages/Documents/Dependency-Injection">inject</a> it and use it to get a cache. Example:</p>

			<pre lang="cs">public class TestAppService : ApplicationService
{
    private readonly ICacheManager _cacheManager;

    public TestAppService(ICacheManager cacheManager)
    {
        _cacheManager = cacheManager;
    }

    public Item GetItem(int id)
    {
        //Try to get from cache
        return _cacheManager
                .GetCache(&quot;MyCache&quot;)
                .Get(id.ToString(), () =&gt; GetFromDatabase(id)) as Item;
    }

    public Item GetFromDatabase(int id)
    {
        //... retrieve item from database
    }
}</pre>
			<p>In this sample, we're injecting <strong>ICacheManager</strong> and getting a 
cache named <strong>MyCache</strong>. Cache names are case sensitive, than means 
			"MyCache" and "MYCACHE" are different caches.</p>

			<div class="bs-callout bs-callout-warning">
				<h4>
					<strong>WARNING: </strong>GetCache Method</h4>
				<p>Do not use <strong>GetCache</strong> method in your constructor. This may dispose the 
	Cache if your class is not singleton.</p>
			</div>

			<h3>ICache</h3>

			<p>ICacheManager.<strong>GetCache</strong> method returns an <strong>ICache</strong>. 
A cache is singleton (per cache name). It is created first time it's 
requested, then returns always the same cache object. So, we can share same 
cache with same name in different classes (clients).</p>
			<p>In the sample code, we see simple usage of ICache.<strong>Get</strong> 
method. It has two arguments:</p>
			<ul>
				<li>
					<strong>key</strong>: A string unique key of an item in the cache.</li>
				<li>
					<strong>factory</strong>: An action which is called if there is no 
	item with the given key. Factory method should create and return the 
	actual item. This is not called if given key has present in the cache.</li>
			</ul>
			<p>ICache interface also has methods like <strong>GetOrDefault</strong>,
				<strong>Set</strong>, <strong>Remove</strong> and <strong>Clear</strong>. 
There are also <strong>async</strong> versions of all methods.</p>

			<h4>ITypedCache</h4>

			<p>
				<strong>ICache </strong>interface works <strong>string</strong> as key 
and <strong>object</strong> as value. <strong>ITypedCache</strong> is a 
wrapper to ICache to provide <strong>type safe</strong>, generic cache. We can 
				use generic GetCache extension method to get an ITypedCache:</p>
			<pre lang="cs">ITypedCache&lt;int, Item&gt; myCache = _cacheManager.GetCache<strong>&lt;int, Item&gt;</strong>(&quot;MyCache&quot;);</pre>
			<p>
				Also, we can use <strong>AsTyped</strong> extension method to 
				convert an existing ICache instance to ITypedCache.</p>

			<h3>Configuration</h3>

			<p>Default cache expire time is 60 minutes. It's sliding. So, if you don't use 
an item in the cache for 60 minutes, it's automatically removed from the cache. 
You can configure it for all caches or for a specific cache.</p>
			<pre>//Configuration for all caches
Configuration.Caching.ConfigureAll(cache =&gt;
{
    cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2);
});

//Configuration for a specific cache
Configuration.Caching.Configure(&quot;MyCache&quot;, cache =&gt;
{
    cache.DefaultSlidingExpireTime = TimeSpan.FromHours(8);
});</pre>
			<p>This code should be placed
				<a href="/Pages/Documents/Module-System#DocModulePreInit">
					<strong>PreInitialize</strong>
				</a> 
method of your module. With such a code, MyCache will have 8 hours expire time 
while all other caches will have 2 hours.</p>
			<p>Your configuration action is called once cache is first created (on 
first request). Configuration is not restricted to DefaultSlidingExpireTime 
only, since cache object is an ICache, you can use it's properties and methods 
freely configure and initialize it.</p>
			<h3>Entity Caching</h3>
			<p>While ASP.NET Boilerplate's cache system is general purpose, 
			there is an <strong>EntityCache </strong> base class that can help you if you want to 
			cache entities. We can use this base class if we get entities by 
			their Ids and we want to <strong>cache them by Id</strong> to not 
			query from database frequently. Assume that we have a Person entity 
			like that:</p>
			<pre lang="cs">public class Person : Entity
{
    public string Name { get; set; }

    public int Age { get; set; }
}</pre>
			<p>And assume that we frequently want to get <strong>Name</strong> of people while we know their 
			<strong>Id</strong>. 
			First, we should create a class to store <strong>cache items</strong>:</p>
			<pre lang="cs"><strong>[AutoMapFrom(typeof(Person))]</strong>
public class PersonCacheItem
{
    public string Name { get; set; }
}
</pre>
			<p>We <strong>should not directly store entities in the cache</strong> since 
			caching may need to <strong>serialize</strong> cached objects and 
			entities may not be serialized (especially if they have navigation 
			properties). That's why we defined a simple (<a href="Data-Transfer-Objects.html">DTO</a> 
			like) class to store data in 
			the cache. We added <strong>
			AutoMapFrom</strong> attribute since we want to use AutoMapper to 
			convert Person entities to PersonCacheItem objects automatically. If we don't use 
			AutoMapper, we should <strong>override MapToCacheItem</strong> 
			method of EntityCache class to manually convert/map it.</p>
			<p>While it's <strong>not required</strong>, we may want to define an interface for 
			our cache class:</p>
			<pre lang="cs">public interface IPersonCache : <strong>IEntityCache&lt;PersonCacheItem&gt;</strong>
{

}</pre>
			<p>Finally, we can create the cache class to cache Person entities:</p>
			<pre lang="cs">public class PersonCache : <strong>EntityCache&lt;Person, PersonCacheItem&gt;</strong>, IPersonCache, <strong>ITransientDependency</strong>
{
    public PersonCache(ICacheManager cacheManager, IRepository&lt;Person&gt; repository)
        : base(cacheManager, repository)
    {

    }
}</pre>
			<p>That's all. Our person cache is ready to use. Cache class can be 
			transient (as in this example) or singleton. This does not mean the 
			cached data is transient. It's always cached globally and accessed 
			thread-safe in your application.</p>
			<p>Now, whenever we 
			need <strong>Name</strong> of a person, we can get it from cache by 
			the person's 
			<strong>Id</strong>. An example class that uses the Person cache:</p>
			<pre lang="cs">public class MyPersonService : ITransientDependency
{
    private readonly IPersonCache _personCache;

    public MyPersonService(<strong>IPersonCache personCache</strong>)
    {
        _personCache = personCache;
    }

    public string GetPersonNameById(int id)
    {
        <strong>return _personCache[id].Name;</strong> //alternative: _personCache.Get(id).Name;
    }
}</pre>
			<p>We simply <a href="Dependency-Injection.html">injected</a> 
			IPersonCache, got the cache item and got the Name property.</p>
			<h4>How EntityCache Works</h4>
			<ul>
				<li>It gets entity from repository (from database) in first 
				call. Then gets from cache in subsequent calls.</li>
				<li>It automatically invalidates cached entity if this entity is 
				updated or deleted. Thus, it will be retrieved from database in 
				the next call.</li>
				<li>It uses IObjectMapper to map entity to cache item. 
				IObjectMapper is implemented by AutoMapper module. So, you need 
				to
				<a href="/Pages/Documents/Data-Transfer-Objects#DocAutoMappingHelpers">
				AutoMapper module</a> if you are using it. You can override 
				MapToCacheItem method to manually map entity to cache item.</li>
				<li>It uses cache class's FullName as cache name. You can change 
				it by passing a cache name to the base constructor.</li>
				<li>It's thread-safe.</li>
			</ul>
			<p>If you need more complex caching requirements, you can extend 
			EntityCache or create your own solution.</p>
			<h3>Redis Cache Integration</h3>
			<p>Default cache manager uses <strong>in-memory</strong> caches. So, it can be a 
			problem if you have more than one concurrent web server running the 
			same application. In that case, you may want to a 
			<strong>distributed/central cache</strong> server. You can use Redis as 
			your cache server 
			easily.</p>
			<p>First, you need to install 
			<a href="https://www.nuget.org/packages/Abp.RedisCache" target="_blank">
			<strong>Abp.RedisCache</strong></a> nuget package to your 
			application (you can install it to your Web project, for example). 
			Then you need to add a <strong>DependsOn</strong> 
			attribute for <strong>AbpRedisCacheModule</strong> and call <strong>UseRedis</strong> 
			extension method in <strong>PreInitialize</strong> method of your
			<a href="Module-System.html">module</a>, as shown below:</p>

		<pre lang="cs">//...other namespaces
<strong>using Abp.Runtime.Caching.Redis;</strong>

namespace MyProject.AbpZeroTemplate.Web
{
    [DependsOn(
        //...other module dependencies
        <strong>typeof(AbpRedisCacheModule)</strong>)]
    public class MyProjectWebModule : AbpModule
    {
        public override void <strong>PreInitialize</strong>()
        {
            //...other configurations
            
            <strong>Configuration.Caching.UseRedis();</strong>
        }
        
        //...other code
    }
}</pre>
		<p>Abp.RedisCache package uses "<strong>localhost</strong>" as <strong>connection string</strong> 
		as default. You can add connection string to your config file to 
		override it. Example:</p>
			<pre lang="xml">&lt;add name=&quot;<strong>Abp.Redis.Cache</strong>&quot; connectionString=&quot;localhost&quot;/&gt;</pre>
			<p>Also, you can add setting to appSettings to set database id of 
			Redis. Example:</p>
			<pre lang="xml">&lt;add key=&quot;<strong>Abp.Redis.Cache.DatabaseId</strong>&quot; value=&quot;2&quot;/&gt;</pre>
			<p>Different database ids are useful to create different key spaces 
			(isolated caches) in same server.</p>
			<p><strong>UseRedis</strong> method has also an overload that takes 
			an action to directly set option values (overrides values in the 
			config file).</p>
			<p>See <a href="http://redis.io/documentation" target="_blank">Redis 
			documentation</a> for more information on Redis and it's 
			configuration.</p>
			<p><strong>Note</strong>: Redis server should be installed and 
			running to use Redis cache in ABP.</p>

		</div>

	</body>

</html>
